<script>
// 导入所有节点组件
import Root from "@/views/process/node/nodes/RootNode.vue";
import Approval from "@/views/process/node/nodes/ApprovalNode.vue";
// 默认配置项
import DefaultProps from "./DefaultNodeProps";
export default {
  name: "ProcessTree",
  components: {
    Root,
    Approval,
  },
  data() {
    return {
      errorValid: []
    };
  },
  computed: {
    nodeMap() {
      return this.$store.state.nodeMap;
    },
    dom() {
      return this.$store.state.process;
    },
  },
  render(h) {
    console.log("渲染流程树render");
    this.nodeMap.clear();
    let processTrees = this.getDomTree(h, this.dom);
    // 插入流程结束节点
    processTrees.push(
      h("div", { style: { "text-align": "center" } }, [
        h("div", {
          class: { "process-end": true },
          domProps: { innerHTML: "流程结束" },
        }),
      ])
    );
    return h("div", { class: { _root: true }, ref: "_root" }, processTrees);
  },
  methods: {
    getDomTree(h, node) {
      this.toMapping(node);
      this.setBtns();
      if (this.isPrimaryNode(node)) {
        // 判断是否为ROOT/APPROVAL节点
        let childDoms = this.getDomTree(h, node.children);
        this.decodeAppendDom(h, node, childDoms);
        return [h("div", { class: { "primary-node": true } }, childDoms)];
      } else {
        // 遍历到了末端，无子节点
        return [];
      }
    },
    // 解码渲染的时候插入dom到同级
    decodeAppendDom(h, node, dom, props = {}) {
      props.config = node;
      dom.unshift(
        h(
          node.type.toLowerCase(),
          {
            props: props,
            ref: node.id,
            key: node.id,
            // 定义事件: 插入节点，删除节点，选中节点
            on: {
              insertNode: (type) => this.insertNode(type, node),
              delNode: () => this.delNode(node),
              selected: () => this.selectNode(node),
            },
          },
          []
        )
      );
    },
    // id映射到map，用来向上遍历
    toMapping(node) {
      if (node && node.id) {
        this.nodeMap.set(node.id, node);
      }
    },
    // 判断是否为主要业务节点
    isPrimaryNode(node) {
      return node && (node.type === "ROOT" || node.type === "APPROVAL");
    },
    // 获取一个随机id
    getRandomId() {
      return `node_${new Date().getTime().toString().substring(5)}${Math.round(
        Math.random() * 9000 + 1000
      )}`;
    },
    // 选中一个节点
    selectNode(node) {
      this.$store.commit("selectedNode", node);
      this.$emit("selectedNode", node);
    },
    // 处理节点插入逻辑
    insertNode(type, parentNode) {
      // 缓存一下后面的节点
      let afterNode = parentNode.children;
      // 插入新节点
      let newId = this.getRandomId();
      parentNode.children = {
        id: newId,
        parentId: parentNode.id,
        props: {},
        type: type,
      };
      switch (type) {
        case "APPROVAL":
          this.insertApprovalNode(parentNode, afterNode);
          break;
        default:
          break;
      }
      // 拼接后续节点
      afterNode.parentId = newId;
      this.$set(parentNode.children, "children", afterNode);
      this.loopModifyName(parentNode, parentNode.children);
      this.$forceUpdate();
    },
    insertApprovalNode(parentNode) {
      this.$set(
        parentNode.children,
        "props",
        this.$deepCopy(DefaultProps.APPROVAL_PROPS)
      );
    },
    // 删除当前节点
    delNode(node) {
      console.log("删除节点", node);
      // 获取该节点的父节点
      let parentNode = this.nodeMap.get(node.parentId);
      if (parentNode) {
        // 不是的话就直接删除
        if (node.children && node.children.id) {
          node.children.parentId = parentNode.id;
        }
        parentNode.children = node.children;
        this.loopModifyName(parentNode, parentNode.children);
        this.$forceUpdate();
      } else {
        this.$message.warning("出现错误，找不到上级节点");
      }
    },
    loopModifyName(parentNode, node) {
      this.forEachNode(parentNode, node, (parent) => {
        let parentNodeName = parent.name;
        let name =
          parentNodeName === "发起人"
            ? "审批人1"
            : "审批人" + (1 + Number(parentNodeName.slice(3)));
        this.$set(parent.children, "name", name);
      });
    },
    setBtns() {
      if (this.nodeMap.size === 6) {
        this.$store.commit("setAddBtn", false);
      } else {
        this.$store.commit("setAddBtn", true);
      }
      if (this.nodeMap.size > 2) {
        this.$store.commit("setDelBtn", true);
      } else {
        this.$store.commit("setDelBtn", false);
      }
    },
    // 校验流程必填
    validateProcess() {
      this.errorValid = [];
      this.validate(this.dom);
      if (this.errorValid.filter(ls => ls === false).length > 0) {
        this.$message.warning("请根据提示完成流程节点设置");
      }
    },
    // 校验所有节点设置
    validate(node) {
      if (this.isPrimaryNode(node)) {
        this.validateNode(node);
        this.validate(node.children);
      }
    },
    validateNode(node) {
      if (this.$refs[node.id].validateSelf) {
        let flag = this.$refs[node.id].validateSelf();
        this.errorValid.push(flag);
      }
    },
    // 更新指定节点的dom
    nodeDomUpdate(node) {
      this.$refs[node.id].$forceUpdate();
    },
    // 给定一个起始节点，遍历内部所有节点
    forEachNode(parent, node, callback) {
      if (this.isPrimaryNode(node)) {
        callback(parent, node);
        this.forEachNode(node, node.children, callback);
      }
    },
  },
  watch: {},
};
</script>

<style lang="less" scoped>
._root {
  margin: 0 auto;
}
.process-end {
  width: 60px;
  margin: 0 auto;
  margin-bottom: 20px;
  border-radius: 15px;
  padding: 5px 10px;
  font-size: small;
  color: #747474;
  background-color: #f2f2f2;
  box-shadow: 0 0 10px 0 #bcbcbc;
}
.primary-node {
  display: flex;
  align-items: center;
  flex-direction: column;
}
.branch-node {
  display: flex;
  justify-content: center;
  /*border-top: 2px solid #cccccc;
  border-bottom: 2px solid #cccccc;*/
}
.branch-node-item {
  position: relative;
  display: flex;
  background: #f5f6f6;
  flex-direction: column;
  align-items: center;
  border-top: 2px solid #cccccc;
  border-bottom: 2px solid #cccccc;
  &:before {
    content: "";
    position: absolute;
    top: 0;
    left: calc(50% - 1px);
    margin: auto;
    width: 2px;
    height: 100%;
    background-color: #cacaca;
  }
  .line-top-left,
  .line-top-right,
  .line-bot-left,
  .line-bot-right {
    position: absolute;
    width: 50%;
    height: 4px;
    background-color: #f5f6f6;
  }
  .line-top-left {
    top: -2px;
    left: -1px;
  }
  .line-top-right {
    top: -2px;
    right: -1px;
  }
  .line-bot-left {
    bottom: -2px;
    left: -1px;
  }
  .line-bot-right {
    bottom: -2px;
    right: -1px;
  }
}
.add-branch-btn {
  position: absolute;
  width: 80px;
  .add-branch-btn-el {
    z-index: 999;
    position: absolute;
    top: -15px;
  }
}

.empty-node {
  display: flex;
  justify-content: center;
  flex-direction: column;
  align-items: center;
}
</style>
